The unofficial DM2 format description
  Uwe Girlich, uwe@planetquake.com
  v1.0.1, 7/15/1998

  This document describes the DM2 file format. This file format is the
  result of ``recording'' a game in Quake II.  This documentation covers
  the Quake II versions 3.05 through 3.17.
  ______________________________________________________________________

  Table of Contents


  1. Introduction

     1.1 Recording and Playback
     1.2 Versions
     1.3 Advertising

  2. File structure

     2.1 General remarks
     2.2 Block of messages
     2.3 Message
     2.4 Auxiliary routines

  3. List of all message types

     3.1 bad
     3.2 muzzleflash
     3.3 muzzlflash2
     3.4 temp_entity
     3.5 layout
     3.6 inventory
     3.7 nop
     3.8 disconnect
     3.9 reconnect
     3.10 sound
     3.11 print
     3.12 stufftext
     3.13 serverdata
     3.14 configstring
     3.15 spawnbaseline
     3.16 centerprint
     3.17 download
     3.18 playerinfo
     3.19 packetentities
     3.20 deltapacketentities
     3.21 frame

  4. Version History and Acknowledgements



  ______________________________________________________________________

  11..  IInnttrroodduuccttiioonn


  11..11..  RReeccoorrddiinngg aanndd PPllaayybbaacckk

  To create a recording of your Quake II play start any map and then use
  the console command _r_e_c_o_r_d _n_a_m_e. This records the game play from your
  point of view into the file demos/name.dm2.  To stop this recording
  use _s_t_o_p or even quit the whole game (_q_u_i_t). To play it back, use the
  command _d_e_m_o_m_a_p _n_a_m_e_._d_m_2 or simply _m_a_p _n_a_m_e_._d_m_2.

  To create a server side recording invoke at the server during a
  running game the console command _s_e_r_v_e_r_r_e_c_o_r_d _n_a_m_e. This records all
  information of all entities in the whole level but no player
  information into the file demos/name.dm2. These recordings are really
  huge!


  11..22..  VVeerrssiioonnss

  In this document I'll discuss the DM2 format used by Quake II. There
  are significant differences between the Quake II test release (engine
  version 3.00) and the CD retail version (3.05). This difference
  consists especially in the reordered message code bytes, so that the
  ``normal codes'' have the values 1 to 5 in 3.05.  There are some more
  differences in the ssppaawwnnbbaasseelliinnee message.  Due to the existence of a
  sole DM2 file in the 3.00 format (packed in the PAK file of the test
  release) and considering the fact, that the test release can't even
  record new ones, I will confine myself to the ``new'' format,
  introduced with the CD retail version 3.05.

  With 3.15 a new kind of DM2 file was introduced: server side
  recordings.  These are for DM2 editors only, since they contain all
  information from all entities but no player information and Quake II
  isn't even able to play them back.

  In 3.17 the server-side recordings became easier to parse because
  sseerrvveerrddaattaa can now be used to distinguish between a client- and
  server-side recording.

  _v_e_r_s_i_o_n                               platform   note
  3.05 x86 Nov 30 1997 RELEASE          Win32      CD retail
  3.06 x86 Dec 9 1997 RELEASE           Win32      first patch
  3.07 x86 Dec 27 1997 RELEASE          Win32      interim release
  3.08 x86 Dec 28 1997 RELEASE          Win32      another interim release
  3.09 x86 Dec 29 1997 RELEASE          Win32      with patch program
  3.10 x86 Jan 4 1998 RELEASE           Win32      last before point release
  3.10 NON-WIN32 Jan 5 1998 NON-WIN32   Linux      first Linux release
  3.12 x86 Feb 16 1998 RELEASE          Win32      point release
  3.13 x86 Feb 23 1998 RELEASE          Win32      point fix release
  3.13 i386 Feb 24 1998 RELEASE         Linux      point fix release
  3.14 i386 Mar 2 1998 RELEASE          Linux      another fix release
  3.14 x86 Mar 2 1998 RELEASE           Win32      another fix release
  3.14 i386 Mar 3 1998 RELEASE          Linux      bug fix release 3.14a
  3.15 x86 May 27 1998 Win32 RELEASE    Win32      mission pack release
  3.15 i386 May 29 1998 Linux           Linux      bug fix release 3.15a
  3.17 i386 Jun 21 1998 Linux           Linux
  3.17 x86 Jun 22 1998 Win32 RELEASE    Win32


                        Covered Quake II versions.


  11..33..  AAddvveerrttiissiinngg

  As the clever reader may know I'm the author of LMPC, the Little Movie
  Processing Centre. With this tool you may

  +o  ``decompile'' an existing DM2 file (3.05 ... 3.17) to a simple text
     file and

  +o  ``compile'' such a (modified) text file back to a binary DM2 file.

     With LMPC it is very easy to analyse a DM2 file but you may change
     it as well and so create a DM2 file of a Quake II game you never
     played. The current version of LMPC can be found at my Demo Specs
     page <http://www.planetquake.com/demospecs>.
  22..  FFiillee ssttrruuccttuurree



  22..11..  GGeenneerraall rreemmaarrkkss

  All multi-byte structures are Intel-ordered (low first).  Descriptive
  sentences in _i_t_a_l_i_c_s are copied from the published game source. There
  are up to now 2 different source packages available from id Software:

  +o  the older from december 1997 with the source of the game library
     and some tools:
     <ftp://ftp.idsoftware.com/pub/quake2/source/q2source_12_11.zip> and

  +o  the newer one from march 1998 with the source of the game library
     only:
     <ftp://ftp.idsoftware.com/pub/quake2/source/q2-3.14-source.exe>

     I usually refer to the files from the newer source but use the
     directory hierarchy from the old source.


  22..22..  BBlloocckk ooff mmeessssaaggeess

  A DM2 file is a set of ``blocks'' of ``messages''. A block consists of
  a 4 byte length entry and the actual messages:


       typedef struct {
                        unsigned long size;
                        unsigned char messages[size];
                      } block_t;





     #define MAX_MSGLEN 1400
        is the maximum message size (real game data in a network
        packet).  The value must be less or equal than 1472 to avoid
        fragmentation of the UDP packets on an Ethernet. The MTU in PPP
        is much smaller and QuakeWorld uses also much bigger network
        packets but the reduced packet size is for LAN play definitely a
        great improvement. In server side recordings there is not such a
        restriction.



          if (serverdata.isdemo == RECORD_CLIENT && block.size>MAX_MSGLEN)
            error("Demo message > MAX_MSGLEN");




  Beginning with engine version 3.05 Quake II uses an empty block with a
  block size of -1 (0xffffffff) as the last block.  This remindes (at
  least) me of the old DOOM LMP end byte (0x80).


  22..33..  MMeessssaaggee

  This is the message structure:




  typedef struct {
                   unsigned char ID;
                   char          messagecontent[???];
                 } message_t;




  The length of a message depends on its type (or ID) but it can't be
  bigger than MAX_MSGLEN, the size of a full block.


  22..44..  AAuuxxiilliiaarryy rroouuttiinneess

  Here comes the definition of some small auxiliary routines to simplify
  the main message description. get_next_unsigned_char,
  get_next_signed_char, get_next_short and get_next_long, get_next_float
  are basic functions and they do exactly what they are called. Please
  note: byte, char or short will be converted to int.

  In the following I often use a count variable


       int i;




  without declaration. I hope this does not confuses you.



       int ReadChar
       {
         return (int) get_next_signed_char;
       }






       int ReadByte
       {
         return (int) get_next_unsigned_char;
       }






       int ReadShort
       {
         return (int) get_next_short;
       }










  int ReadLong
  {
    return (int)get_next_long;
  }






       float ReadFloat
       {
         return get_next_float;
       }





  The string reading stops at '\0' or after 0x7FF bytes. The internal
  buffer has only 0x800 bytes available.



       char* ReadString
       {
         char* string_pointer;
         char string_buffer[0x800];

         string_pointer=string_buffer;
         for (i=0 ; i<0x7FF ; i++, string_pointer++) {
           if (! (*string_pointer = ReadChar) ) break;
         }
         *string_pointer = '\0';
         return strdup(string_buffer);
       }






       ReadPosition(vec_t* pos)
       {
         for (i=0 ; i<3 ; i++) pos[i] = (vec_t) ReadShort * 0.125;
       }




  A direction for temporary entities is stored in a single byte.  The
  162 possible orientations are precalculated and stored in a template
  list.  Each direction is represented by a normalised vector. The
  template list can be found in the source, utils3/qdata/anorms.h

  I tried to reproduce the template list but I didn't find the algorithm
  behind it. Take it as it is: even Quake II uses the list and
  calculates with dot products the best fitting direction.








  ReadDir(vec_t* pos)
  {
    #define NUMVERTEXNORMALS 162
    int code;
    float avertexnormals[NUMVERTEXNORMALS][3] = {
      #include "utils3/qdata/anorms.h"
    }
    code = ReadByte;
    if (code >= NUMVERTEXNORMALS) error("MSF_ReadDir: out of range");
    pos[0] = avertexnormals[code][0];
    pos[1] = avertexnormals[code][1];
    pos[2] = avertexnormals[code][2];
  }




  Note: A signed angle in a single byte. There are only 256 possible
  direction to look into.



       vec_t ReadAngle
       {
         return (vec_t) ReadChar * 360.0 / 256.0;
       }






       vec_t ReadAngle16
       {
         return (vec_t) ReadShort * 360.0 / 65536.0;
       }





  33..  LLiisstt ooff aallll mmeessssaaggee ttyyppeess

  The easiest way to explain a message is to give a short C like program
  fragment to parse such a message. It is not really the same code base
  as in LMPC but it should be _v_e_r_y similar. Each message can be
  described by its ID or its name.



  33..11..  bbaadd


     ID 0x00


     ppuurrppoossee
        Something is bad. This message should never appear.


     ppaarrssee rroouuttiinnee


          error("CL_ParseServerMessage: Illegible server message\n");


  33..22..  mmuuzzzzlleeffllaasshh


     ID 0x01

     ppuurrppoossee
        _m_u_z_z_l_e _f_l_a_s_h_e_s _/ _p_l_a_y_e_r _e_f_f_e_c_t_s.


     vvaarriiaabblleess

        long entity;
           is the player entity with the effect.

        long value;
           is the muzzle flash / player effect.  The value should be one
           of the MZ_ constants (source, game/q_shared.h, 574 - 590). It
           may be ``OR''ed with


             #define MZ_SILENCED 128



        if the player uses the Silencer.


     ppaarrssee rroouuttiinnee


          entity = ReadShort;
          value = ReadByte;






  33..33..  mmuuzzzzllffllaasshh22


     ID 0x02


     ppuurrppoossee
        _m_o_n_s_t_e_r _m_u_z_z_l_e _f_l_a_s_h_e_s.


     vvaarriiaabblleess

        long entity;
           is the monster entity with the effect.

        long value;
           is the monster muzzle flash.  The value should be one of the
           MZ2_ constants (source, game/q_shared.h, 596 - 747).


     ppaarrssee rroouuttiinnee


          entity = ReadShort;
          value = ReadByte;



  33..44..  tteemmpp__eennttiittyy


     ID 0x03


     ppuurrppoossee
        Spawns a temporary entity.  _T_e_m_p _e_n_t_i_t_y _e_v_e_n_t_s _a_r_e _f_o_r _t_h_i_n_g_s
        _t_h_a_t _h_a_p_p_e_n _a_t _a _l_o_c_a_t_i_o_n _s_e_p_e_r_a_t_e _f_r_o_m _a_n_y _e_x_i_s_t_i_n_g _e_n_t_i_t_y_.
        _T_e_m_p_o_r_a_r_y _e_n_t_i_t_y _m_e_s_s_a_g_e_s _a_r_e _e_x_p_l_i_c_i_t_l_y _c_o_n_s_t_r_u_c_t_e_d _a_n_d
        _b_r_o_a_d_c_a_s_t_.


     vvaarriiaabblleess

        long entitytype;
           is the type of the temporary entity.  entitytype should be
           one of the TE_ constants (source, game/q_shared.h, 758 -
           788). They are defined with a typedef and not as #define but
           who cares?  There are many different kinds of temporary
           entities in Quake II:

           ppooiinntt eennttiittyy
              is a point like entity like explosions or teleport fog. It
              needs a position.

              #define TE_EXPLOSION1 5
                 boss, barrels etc.  explosion

              #define TE_EXPLOSION2 6
                 barrels explosion

              #define TE_ROCKET_EXPLOSION 7
                 rocket explosion

              #define TE_GRENADE_EXPLOSION 8
                 grenade explosion

              #define TE_ROCKET_EXPLOSION_WATER
                 17" rocket explosion under water

              #define TE_GRENADE_EXPLOSION_WATER
                 18" grenade explosion under water

              #define TE_BFG_EXPLOSION 20
                 BFG explosion

              #define TE_BFG_BIGEXPLOSION 21
                 big BFG explosion

              #define TE_BOSSTPORT 22
                 boss teleports away


           iimmppaacctt eennttiittyy
              is a small point like entity, spawned on an impact of a
              bullet etc. It needs a position (often a trace end) and a
              direction from there.

              #define TE_GUNSHOT 0
                 hit with Machine Gun and Chain Gun

              #define TE_BLOOD 1
                 clients and monsters bleed when hit


              #define TE_BLASTER 2
                 hit with Blaster

              #define TE_SHOTGUN 4
                 hit with Shotgun

              #define TE_SPARKS 9
                 hit someone

              #define TE_SCREEN_SPARKS 12
                 hit on an Energy Armor

              #define TE_SHIELD_SPARKS 13
                 hit on a different Energy Armor

              #define TE_BULLET_SPARKS 14
                 hit someone with bullets

              #define TE_GREENBLOOD 27
                 new in 3.12, not used


           lliinnee eennttiittyy
              is a 2 dimensional entity. It needs an origin and an end
              position.

              #define TE_RAILTRAIL 3
                 trail of the Rail Gun (blue)

              #define TE_BUBBLETRAIL 11
                 shot with a bullet through water

              #define TE_BFG_LASER 23
                 new in 3.12, BFG laser

              #define TE_PLASMATRAIL 26
                 new in 3.12, not used


           ssppeecciiaall eennttiittyy
              is a entity which doesn't fit into the other categories.

              #define TE_SPLASH 10
                 creates a particle splash effect

              #define TE_LASER_SPARKS 15
                 laser hits a wall

              #define TE_PARASITE_ATTACK 16
                 parasite attack

              #define TE_MEDIC_CABLE_ATTACK
                 19" medic cable attac

              #define TE_GRAPPLE_CABLE 24
                 new in 3.12, used in CFT

              #define TE_WELDING_SPARKS 25
                 new in 3.12, not used

              #define TE_28 28
                 new in 3.15, unknown

              #define TE_29 29
                 new in 3.15, unknown

           The sounds field of the special TE_SPLASH temporary entity
           should be one of the SPLASH_ constants (source,
           game/q_shared.h, 790 - 796).


        vec3_t origin;
           is the origin of the temporary entity.


        vec3_t trace_endpos;
           is the end position of the line like temporary entity.


        vec3_t offset;
           is an additional offset for the CTF grappling hook.


        vec3_t movedir;
           is the moving direction for the temporary entity.


        int count;
           is a number for multi-particle temporary entities.


        int color;
           is the colour of the ``Laser Sparks''.


     ppaarrssee rroouuttiinnee




































     entitytype = ReadByte;
     switch (entitytype) {
       // point entity
       case TE_EXPLOSION1:
       case TE_EXPLOSION2:
       case TE_ROCKET_EXPLOSION:
       case TE_GRENADE_EXPLOSION:
       case TE_ROCKET_EXPLOSION_WATER:
       case TE_GRENADE_EXPLOSION_WATER:
       case TE_BFG_EXPLOSION:
       case TE_BFG_BIGEXPLOSION:
       case TE_BOSSTPORT:
       case TE_28:
         ReadPosition(origin);
       break;
       // impact entity
       case TE_GUNSHOT:
       case TE_BLOOD:
       case TE_BLASTER:
       case TE_SHOTGUN:
       case TE_SPARKS:
       case TE_SCREEN_SPARKS:
       case TE_SHIELD_SPARKS:
       case TE_BULLET_SPARKS:
       case TE_GREENBLOOD:
         ReadPosition(origin);
         ReadDir(movedir);
       break;
       // line entity
       case TE_RAILTRAIL:
       case TE_BUBBLETRAIL:
       case TE_BFG_LASER:
       case TE_PLASMATRAIL:
         ReadPosition(origin);
         ReadPosition(trace_endpos);
       break;
       // special entity
       case TE_SPLASH:
         count = ReadByte;
         ReadPosition(origin);
         ReadDir(movedir);
         sounds = ReadByte;
       break;
       case TE_LASER_SPARKS:
       case TE_WELDING_SPARKS:
       case TE_29:
         count = ReadByte;
         ReadPosition(origin);
         ReadDir(movedir);
         color = ReadByte;
       break;
       case TE_PARASITE_ATTACK:
       case TE_MEDIC_CABLE_ATTACK:
         entity = ReadShort;
         ReadPosition(origin);
         ReadPosition(trace_endpos);
       break;
       case TE_GRAPPLE_CABLE:
         entity = ReadShort;
         ReadPosition(origin);
         ReadPosition(trace_endpos);
         ReadPosition(offset);
       break;
       default:
         error("CL_ParseTEnt: bad type");
       break;
     }






  33..55..  llaayyoouutt


     ID 0x04


     ppuurrppoossee
        This message displays the Field Computer (``cmd help'', bound to
        F1).  It contains the summary screen (Deathmatch Scoreboard or
        single player secrets, goals etc.). It stores the message only
        on the client siede.  The actual display will be triggered by
        the ppllaayyeerriinnffoo message with a special stats command.


     vvaarriiaabbllee

        char text[MAX_MSGLEN];
           is the summary screen text with some kind of control
           characters. The control language is very simple. Read some
           examples in the source, game/p_hud.c, functions
           DeathmatchScoreboardMessage and HelpComputer.



     ppaarrssee rroouuttiinnee


          text = ReadString;






  33..66..  iinnvveennttoorryy


     ID 0x05


     ppuurrppoossee
        Tells the clients its inventory.


     vvaarriiaabbllee

        int inventory[MAX_ITEMS];
           is the player's inventory array.


             #define MAX_ITEMS 256



        is the number different items in the inventory.

        The inventory concept of Quake II is very open and expandable.
        In an global array (source, game/g_items.c, 1100 - 2041)

        gitem_t itemlist[];




        is the list of all possible things a player can pickup and carry
        around. This array will be filled at compile time.  In the
        inventory array are stored how many of each thing of the item-
        list a players carries. The server tells the meaning of each
        index with ccoonnffiiggssttrriinngg messages.  I give the original table for
        itemlist. Every modification can change it totally and it
        changed indeed from 3.05 to 3.12.

                        value    purpose
                            0    not used
                            1    Body Armor
                            2    Combat Armor
                            3    Jacket Armor
                            4    Armor Shard
                            5    Power Screen
                            6    Power Shield
                            7    Blaster
                            8    Shotgun
                            9    Super Shotgun
                           10    Machinegun
                           11    Chaingun
                           12    Grenades
                           13    Grenade Launcher
                           14    Rocket Launcher
                           15    HyperBlaster
                           16    Railgun
                           17    BFG10K
                           18    Shells
                           19    Bullets
                           20    Cells
                           21    Rockets
                           22    Slugs
                           23    Quad Damage
                           24    Invulnerability
                           25    Silencer
                           26    Rebreather
                           27    Environment Suit
                           28    Ancient Head
                           29    Adrenaline
                           30    Bandolier
                           31    Ammo Pack
                           32    Data CD
                           33    Power Cube
                           34    Pyramid Key
                           35    Data Spinner
                           36    Security Pass
                           37    Blue Key
                           38    Red Key
                           39    Commander's Head
                           40    Airstrike Marker
                           41    Health


                       Standard inventory entries.


     ppaarrssee rroouuttiinnee


          for (i=0 ; i<MAX_ITEMS ; i++) inventory[i] = ReadShort;

  33..77..  nnoopp


     ID 0x06


     ppuurrppoossee
        No operation.


     ppaarrssee rroouuttiinnee
        none



  33..88..  ddiissccoonnnneecctt


     ID 0x07


     ppuurrppoossee
        Diconnect from the server.


     ppaarrssee rroouuttiinnee


          print("Server disconnected\n");






  33..99..  rreeccoonnnneecctt


     ID 0x08


     ppuurrppoossee
        Reconnect to the server.


     ppaarrssee rroouuttiinnee


          print("Server disconnected, reconnecting\n");






  33..1100..  ssoouunndd


     ID 0x09


     ppuurrppoossee
        Plays a sound.



     vvaarriiaabblleess

        long mask;
           is a bit mak to reduce the network traffic.

        long soundnum;
           is the index in the precache sound table.

        float vol;
           is the volume of the sound (0.0 off, 1.0 max).

        float attenuation;
           is the attenuation of the sound.  attenuation should have one
           of the ATTN_ constants (source, game/q_shared.h, 813 - 816).

           #define ATTN_NONE 0
              _f_u_l_l _v_o_l_u_m_e _t_h_e _e_n_t_i_r_e _l_e_v_e_l

           #define ATTN_NORM 1
              the normal attenuation

           #define ATTN_IDLE 2
              for idle monsters

           #define ATTN_STATIC 3
              _d_i_m_i_n_i_s_h _v_e_r_y _r_a_p_i_d_l_y _w_i_t_h _d_i_s_t_a_n_c_e

        float timeofs;
           is the offset in seconds between the frame start and the
           sound start.  It is 0 in the entire source.

        long channel;
           is the sound channel. There are 8 possible sound channels for
           each entity in Quake II (0-7) but it uses 5 only.  channel
           should be one of the CHAN_ constants (source,
           game/q_shared.h, 802 - 806).

           #define CHAN_AUTO 0
              selects a channel automatically

           #define CHAN_WEAPON 1
              weapon use sounds

           #define CHAN_VOICE 2
              pain calls

           #define CHAN_ITEM 3
              item get sounds

           #define CHAN_BODY 4
              jump and fall sounds

        long entity;
           is the entity which caused the sound.  The maximum value of
           entity is


             #define MAX_EDICTS 1024



        .

        vec3_t origin;
           is the origin of the sound.

     ppaarrssee rroouuttiinnee


          long entity_channel; // combined variable

          mask = ReadByte;
          soundnum = ReadByte;
          vol = (mask & 0x01) ? ((float)ReadByte / 255.0) : (1.0);
          attenuation = (mask & 0x02) ? ((float)ReadByte / 64.0) : (1.0);
          timeofs = (mask & 0x10) ? ((float)ReadByte * 0.001) : (0.0);
          if (mask & 0x08) {
            entity_channel = ReadShort;
            entity = (entity_channel >> 3);
            channel = entity_channel & 0x07;
            if (entity > MAX_EDICTS) {
              error("CL_ParseStartSoundPacket: ent = %i", entity);
            }
          } else {
            channel = 0;
            entity = 0;
          }
          if (mask & 0x04) {
            ReadPosition(origin);
          }






  33..1111..  pprriinntt


     ID 0x0A


     ppuurrppoossee
        Prints a text at the top of the screen.


     vvaarriiaabblleess

        long level;
           is the print level.  level should be one of the following:

           #define PRINT_LOW 0
              pickup messages

           #define PRINT_MEDIUM 1
              death messages

           #define PRINT_HIGH 2
              critical messages

           #define PRINT_CHAT 3
              chat messages

        char string[MAX_MESSAGE_SIZE];
           is the the text to be displayed.



     ppaarrssee rroouuttiinnee



     level = ReadByte;
     if (level == PRINT_CHAT) sound("misc/talk.wav");
     string = ReadString;





  33..1122..  ssttuufffftteexxtt


     ID 0x0B


     ppuurrppoossee
        The client transfers the text to the console and runs it.


     vvaarriiaabblleess

        char* text;
           is the command, which the client has to execute.


     ppaarrssee rroouuttiinnee


          text=ReadString;






  33..1133..  sseerrvveerrddaattaa


     ID 0x0C


     ppuurrppoossee
        Set some global info.


     vvaarriiaabblleess

        long serverversion;
           is the protocol version coming from the server.

                             game    protocol
                             3.00    25
                             3.05    26
                             3.06    26
                             3.07    27
                             3.08    27
                             3.09    28
                             3.10    30
                             3.12    31
                             3.13    31
                             3.14    31
                             3.15    32
                             3.17    33


                  Quake II values for PROTOCOL_VERSION.

        long key;
           some kind of key. Will be used again later in a ssttuufffftteexxtt
           message for the login hand-shake.


        long isdemo;
           indicates the demo type. Possible values are:

           #define RECORD_NETWORK 0
              data actually over the wire (proxy)

           #define RECORD_CLIENT  1
              recorded on the client side.  Containes information in the
              direct neighborhood of the recording player.

           #define RECORD_SERVER  2
              recorded on the server side.  Containes all information on
              all entities in the level.These files tend to become very
              large. They can't be played back by Quake II directly.
              This value appears in 3.17 but server side recordings work
              from 3.15 on.  This variable is sometimes called
              attractloop for whatever reason.


        char* game;
           is the game directory (may be empty).


        long client;
           is the client id.


        char* mapname;
           is the name of the map.


        int compatible;
           compatibility with the CD retail version 3.05 (protocol 26).
           How to set this? ??FIXME??



     ppaarrssee rroouuttiinnee


          log("Serverdata packet received.\n");
          serverversion = ReadLong;
          if (!compatible) {
            if (serverversion != PROTOCOL_VERSION)
              error("Server returned version %i, not %i", serverversion, PROTOCOL_VERSION);
            }
          }
          key = ReadLong;
          isdemo = ReadByte;
          game = ReadString;
          client = ReadShort;
          mapname = ReadString;









  33..1144..  ccoonnffiiggssttrriinngg


     ID 0x0D


     ppuurrppoossee
        _c_o_n_f_i_g _s_t_r_i_n_g_s _a_r_e _a _g_e_n_e_r_a_l _m_e_a_n_s _o_f _c_o_m_m_u_n_i_c_a_t_i_o_n _f_r_o_m _t_h_e
        _s_e_r_v_e_r _t_o _a_l_l _c_o_n_n_e_c_t_e_d _c_l_i_e_n_t_s_.  _E_a_c_h _c_o_n_f_i_g _s_t_r_i_n_g _c_a_n _b_e _a_t
        _m_o_s_t MAX_QPATH characters.


     vvaarriiaabblleess

        int index;
           is the number of the config string.  The following constants
           (source, game/q_shared.h, 875 - 891) determine where to find
           something in the full array of config strings.

           #define CS_NAME 0
              is the name of the level.

           #define CS_CDTRACK 1
              is the audio CD track for this level.

           #define CS_SKY 2
              is the sky texture.

           #define CS_SKYAXIS 3
              is the sky axis in the _%_f _%_f _%_f _f_o_r_m_a_t.

           #define CS_SKYROTATE 4
              is the rotation speed in the format %f.

           #define CS_STATUSBAR 5
              is the start of the list of _d_i_s_p_l_a_y _p_r_o_g_r_a_m _s_t_r_i_n_gs for
              the statusbar.

           #define CS_MAXCLIENTS 30
              is the current maximum number of clients on a server.

           #define CS_MAPCHECKSUM 31
              is the map checksum _f_o_r _c_a_t_c_h_i_n_g _c_h_e_a_t_e_r _m_a_p_s.

           #define CS_MODELS 32
              is the start of the model precache list.

           #define MAX_MODELS 256
              is the maximum number of the models in the precache list.

           #define CS_SOUNDS (CS_MODELS+MAX_MODELS)
              (288) is the start of the sound precache list.

           #define MAX_SOUNDS 256
              is the maximum number of the sounds in the precache list.

           #define CS_IMAGES (CS_SOUNDS+MAX_SOUNDS)
              (544) is the start of the image list.

           #define MAX_IMAGES 256
              is the maximum numer of the images.

           #define CS_LIGHTS (CS_IMAGES+MAX_IMAGES)
              (800) is the start of the light styles list.


           #define MAX_LIGHTSTYLES 256
              is the maximum number of the light styles.

           #define CS_ITEMS (CS_LIGHTS+MAX_LIGHTSTYLES)
              (1056) is the start of the items list.

           #define MAX_ITEMS 256
              is the maximum number of items in the inventory list.

           #define CS_PLAYERSKINS (CS_ITEMS+MAX_ITEMS)
              (1312) is the start of the player skin list.

           #define MAX_CLIENTS 256
              is the maximum number of players.

           #define MAX_CONFIGSTRINGS (CS_PLAYERSKINS+MAX_CLIENTS)
              (1568) is the maximum number of config strings.


        char string[MAX_QPATH];
           is the corresponding config string.


             #define MAX_QPATH 64



        is the maximum length of a config string.



     ppaarrssee rroouuttiinnee


          index = ReadShort;
          if (index > MAX_CONFIGSTRINGS) error("configstring > MAX_CONFIGSTRINGS");
          string = ReadString;






  33..1155..  ssppaawwnnbbaasseelliinnee


     ID 0x0E


     ppuurrppoossee
        Spawns a new entity.


     vvaarriiaabblleess

        long mask;
           is a bit-mask to reduce the network traffic.

        long entity;
           is the number of the entity.

        vec3_t origin;
           is the origin.

        vec3_t angles;
           is the orientation.
        vec3_t old_origin;
           is the old origin _f_o_r _l_e_r_p_i_n_g. It is used for client-side
           prediction and interpolation calculations. To compress a DM2
           file, just leave it out, if the last frame had a origin entry
           for the entity in question. It is used with ccll__nnooddeellttaa 11
           only. From 3.17 on old_origin is used for player entities
           only.

        long modelindex;
           is the model index.

        long modelindex2;
           is _w_e_a_p_o_n_s_, _C_T_F_, _f_l_a_g_s_, _e_t_c.

        long modelindex3;
           is _w_e_a_p_o_n_s_, _C_T_F_, _f_l_a_g_s_, _e_t_c.

        long modelindex4;
           is _w_e_a_p_o_n_s_, _C_T_F_, _f_l_a_g_s_, _e_t_c.

        long frame;
           is the frame of the model.

        long skin;
           is the number of the skin for the model.

        long effects;
           _E_f_f_e_c_t_s _a_r_e _t_h_i_n_g_s _h_a_n_d_l_e_d _o_n _t_h_e _c_l_i_e_n_t _s_i_d_e _(_l_i_g_h_t_s_,
           _p_a_r_t_i_c_l_e_s_, _f_r_a_m_e _a_n_i_m_a_t_i_o_n_s_) _t_h_a_t _h_a_p_p_e_n _c_o_n_s_t_a_n_t_l_y _o_n _t_h_e
           _g_i_v_e_n _e_n_t_i_t_y_.  _A_n _e_n_t_i_t_y _t_h_a_t _h_a_s _e_f_f_e_c_t_s _w_i_l_l _b_e _s_e_n_t _t_o _t_h_e
           _c_l_i_e_n_t _e_v_e_n _i_f _i_t _h_a_s _a _z_e_r_o _i_n_d_e_x _m_o_d_e_l_. The bit-mask
           effects holds the EF_ constants (source, game/q_shared.h, 529
           - 549).)

        long renderfx;
           are some special render flags.  The bit-mask renderfx holds
           the RF_ constants (source, game/q_shared.h, 553 - 565).

        long solid;
           _f_o_r _c_l_i_e_n_t _s_i_d_e _p_r_e_d_i_c_t_i_o_n_, _8_*_(_b_i_t_s _0_-_4_) _i_s _x_/_y _r_a_d_i_u_s
           _8_*_(_b_i_t_s _5_-_9_) _i_s _z _d_o_w_n _d_i_s_t_a_n_c_e_, _8_(_b_i_t_s_1_0_-_1_5_) _i_s _z _u_p

        long sound;
           _f_o_r _l_o_o_p_i_n_g _s_o_u_n_d_s_, _t_o _g_u_a_r_a_n_t_e_e _s_h_u_t_o_f_f

        long event;
           _i_m_p_u_l_s_e _e_v_e_n_t_s _-_- _m_u_z_z_l_e _f_l_a_s_h_e_s_, _f_o_o_t_s_t_e_p_s_, _e_t_c _e_v_e_n_t_s _o_n_l_y
           _g_o _o_u_t _f_o_r _a _s_i_n_g_l_e _f_r_a_m_e_, _t_h_e_y _a_r_e _a_u_t_o_m_a_t_i_c_a_l_l_y _c_l_e_a_r_e_d
           _e_a_c_h _f_r_a_m_e event should have one of the following values
           (source, game/q_shared.h, 901 - 910):


             typedef enum
             {
                     EV_NONE,             // 0
                     EV_ITEM_RESPAWN,     // 1
                     EV_FOOTSTEP,         // 2
                     EV_FALLSHORT,        // 3
                     EV_FALL,             // 4
                     EV_FALLFAR,          // 5
                     EV_PLAYER_TELEPORT   // 6
             } entity_event_t;




     ppaarrssee rroouuttiinnee


          mask = ReadByte;
          if (mask & 0x00000080) mask |= (ReadByte <<  8);
          if (mask & 0x00008000) mask |= (ReadByte << 16);
          if (mask & 0x00800000) mask |= (ReadByte << 24);
          entity = (mask & 0x00000100) ? ReadShort : ReadByte;
          if (mask & 0x00000800) modelindex = ReadByte;
          if (mask & 0x00100000) modelindex2 = ReadByte;
          if (mask & 0x00200000) modelindex3 = ReadByte;
          if (mask & 0x00400000) modelindex4 = ReadByte;
          if (mask & 0x00000010) frame = ReadByte;
          if (mask & 0x00020000) frame = ReadShort;
          if (mask & 0x00010000) {
            if (mask & 0x02000000) skin = ReadLong;
            else skin = ReadByte;
          }
          else {
            if (mask & 0x02000000) skin = ReadShort;
          }
          if (mask & 0x00004000) {
            if (mask & 0x00080000) effects = ReadLong;
            else effects = ReadByte;
          }
          else {
            if (mask & 0x00080000) effects = ReadShort;
          }
          if (mask & 0x00001000) {
            if (mask & 0x00040000) renderfx = ReadLong;
            else renderfx = ReadByte;
          }
          else {
            if (mask & 0x00040000) renderfx = ReadShort;
          }
          if (mask & 0x00000001) origin[0] = ReadCoord;
          if (mask & 0x00000002) origin[1] = ReadCoord;
          if (mask & 0x00000200) origin[2] = ReadCoord;
          if (mask & 0x00000400) angles[0] = ReadAngle;
          if (mask & 0x00000004) angles[1] = ReadAngle;
          if (mask & 0x00000008) angles[2] = ReadAngle;
          if (mask & 0x01000000) ReadPosition(old_origin);
          if (mask & 0x04000000) sound = ReadByte;
          event = (mask & 0x00000020) ? ReadByte : 0;
          if (mask & 0x08000000) solid = ReadShort;





  33..1166..  cceenntteerrpprriinntt


     ID 0x0F


     ppuurrppoossee
        Prints the specified text at the centre of the screen. There is
        only one text line with a maximum of 40 characters. To print
        more than this one line, use `\n' in a single cceenntteerrpprriinntt
        message for a new line. Every text line (the first 40
        characters) will be centred horizontally.


     vvaarriiaabblleess

        char* text;
           is the text to be displayed.


     ppaarrssee rroouuttiinnee


          text = ReadString;






  33..1177..  ddoowwnnllooaadd


     ID 0x10


     ppuurrppoossee
        Download a file (sound, model etc.) from the server. It needs at
        least version 3.15 to transfer any data. There is no position
        information in the packet, so the client can't rearrange
        packets, which arrive in the wrong order. Therefore all download
        network packets are reliable packets and they need the usual
        acknowledgement.


     vvaarriiaabblleess

        long size;
           is the number of bytes transferred in the current packet.


        long percent;
           is the total amount sended in percent.


        char* downloadbuffer;
           is a buffer for downloaded files.


        char* filename;
           is the name for the downloaded file.  How does the client
           know it? ??FIXME??


        FILE* fp;
           is the file pointer for the downloaded file.


     ppaarrssee rroouuttiinnee













     size = ReadShort;
     percent=ReadByte;
     if (size == -1) {
       error("File not found.\n");
     }
     if (serverdata.serverversion >= 32) { /* from version 3.15 on */
       if (percent == 0) {
         fp = fopen(filename, "wb");
       }
       for ( i=0 ; i<size ; i++ ) {
         downloadbuffer[i] = ReadByte;
       }
       fwrite(fp, size, 1, downloadbuffer);
       if (percent != 100) {
         servercommand("nextdl"); /* ask for the next part */
       }
       else {
         fclose(fp);
       }
     }






  33..1188..  ppllaayyeerriinnffoo


     ID 0x11


     ppuurrppoossee
        Player info. _H_a_v_e _t_o come directly after a ffrraammee message in
        client recording. There is no such message in server side
        recordings since there is no special player who does the
        recording.


     vvaarriiaabblleess

        long mask;
           is a bit mask to reduce the network traffic.

        long mask2;
           is a bit mask to reduce the network traffic.

        long pm_type;
           is important for client side prediction and should be one of
           the PM_ constants (source, game/q_shared.h, 436 - 445).

        vec3_t origin;
           is the origin.

        vec3_t velocity;
           is the velocity.

        byte pm_flags;
           _d_u_c_k_e_d_, _j_u_m_p___h_e_l_d_, _e_t_c and should be one of the PMF_
           constants (source, game/q_shared.h, 448 - 454).

        byte pm_time;
           is unknown (_e_a_c_h _u_n_i_t _= _8 _m_s).

        short gravity;
           is the gravity (800, cvar sv_gravity).
        vec3_t delta_angles;
           _a_d_d _t_o _c_o_m_m_a_n_d _a_n_g_l_e_s _t_o _g_e_t _v_i_e_w _d_i_r_e_c_t_i_o_n_, _c_h_a_n_g_e_d _b_y
           _s_p_a_w_n_s_, _r_o_t_a_t_i_n_g _o_b_j_e_c_t_s_, _a_n_d _t_e_l_e_p_o_r_t_e_r_s

        vec3_t viewangles;
           _f_o_r _f_i_x_e_d _v_i_e_w_s

        vec3_t viewoffset;
           _a_d_d _t_o pmovestate->origin

        vec3_t kick_angles;
           _a_d_d _t_o _v_i_e_w _d_i_r_e_c_t_i_o_n _t_o _g_e_t _r_e_n_d_e_r _a_n_g_l_e_s _s_e_t _b_y _w_e_a_p_o_n
           _k_i_c_k_s_, _p_a_i_n _e_f_f_e_c_t_s_, _e_t_c

        vec3_t gunangles;
           direction of weapon

        vec3_t gunoffset;
           offset of weapon

        int gunindex;
           model index of weapon

        int gunframe;
           frame of weapon

        float blend[4];
           _r_g_b_a _f_u_l_l _s_c_r_e_e_n _e_f_f_e_c_t

        long fov;
           _h_o_r_i_z_o_n_t_a_l _f_i_e_l_d _o_f _v_i_e_w. Since the field of view is no
           client side variable (as it is in Quake), it is much easier
           to create zoom effects in movies.

        int rdflags;
           _r_e_f_d_e_f _f_l_a_g_s and should be one of the RDF_ constants (source,
           game/q_shared.h, 568 - 569).

        short stats[MAX_STATS];
           _f_a_s_t _s_t_a_t_u_s _b_a_r _u_p_d_a_t_e_s Each entry in this array stays for
           something on the statusbar. The value of an icon entry is the
           image index defined in a ccoonnffiiggssttrriinngg message.  A value of 0
           on an icon entry switches the icon off.  (source,
           game/q_shared.h, 820 - 837)

           #define MAX_STATS 32
              maximum number of things in the status bar

           #define STAT_HEALTH_ICON 0
              health icon image

           #define STAT_HEALTH 1
              health value

           #define STAT_AMMO_ICON 2
              ammo icon image

           #define STAT_AMMO 3
              ammo value

           #define STAT_ARMOR_ICON 4
              armour icon

           #define STAT_ARMOR 5
              armour value

           #define STAT_SELECTED_ICON 6
              icon image of the selected weapon

           #define STAT_PICKUP_ICON 7
              icon image of a recently gotten thing

           #define STAT_PICKUP_STRING 8
              ccoonnffiiggssttrriinngg index to describe the recently gotten thing,
              0 = string off

           #define STAT_TIMER_ICON 9
              icon image of timed object (Quad Damage, Invulnerability
              etc.)

           #define STAT_TIMER 10
              timer value for a timed object (in seconds)

           #define STAT_HELPICON 11
              help icon: 0 off, 1 on

           #define STAT_SELECTED_ITEM 12
              item number of the selected weapon

           #define STAT_LAYOUTS 13
              layout activator: 0 off, 1 display help/summary screen, 2
              display inventory

           #define STAT_FRAGS 14
              client score value

           #define STAT_FLASHES 15
              _f_l_a_s_h _t_h_e _b_a_c_k_g_r_o_u_n_d_s _b_e_h_i_n_d _t_h_e _s_t_a_t_u_s _n_u_m_b_e_r_s_, _c_l_e_a_r_e_d
              _e_a_c_h _f_r_a_m_e_, _1 _= _h_e_a_l_t_h_, _2 _= _a_r_m_o_r, 0 = off



     ppaarrssee rroouuttiinnee





























     mask = ReadShort;
     if (mask & 0x0001) pm_type = ReadByte;
     if (mask & 0x0002)
       ReadPostion(origin);
     if (mask & 0x0004)
       ReadPosition(velocity);
     if (mask & 0x0008) teleport_time = ReadByte;
     if (mask & 0x0010) pm_flags = ReadByte;
     if (mask & 0x0020) gravity = ReadShort;
     if (mask & 0x0040) {
       delta_angles[0] = ReadAngle16;
       delta_angles[1] = ReadAngle16;
       delta_angles[2] = ReadAngle16;
     }
     if (mask & 0x0080) {
       viewoffset[0] = ReadChar / 4.0;
       viewoffset[1] = ReadChar / 4.0;
       viewoffset[2] = ReadChar / 4.0;
     }
     if (mask & 0x0100) {
       viewangles[0] = ReadAngle16;
       viewangles[1] = ReadAngle16;
       viewangles[2] = ReadAngle16;
     }
     if (mask & 0x0200) {
       kick_angles[0] = ReadChar / 4.0;
       kick_angles[1] = ReadChar / 4.0;
       kick_angles[2] = ReadChar / 4.0;
     }
     if (mask & 0x1000) gunindex = ReadByte;
     if (mask & 0x2000) {
       gunframe = ReadByte;
       gunoffset[0] = ReadChar / 4.0;
       gunoffset[1] = ReadChar / 4.0;
       gunoffset[2] = ReadChar / 4.0;
       gunangles[0] = ReadChar / 4.0;
       gunangles[1] = ReadChar / 4.0;
       gunangles[2] = ReadChar / 4.0;
     }
     if (mask & 0x0400) {
       blend[0] = ReadByte / 255.0;
       blend[1] = ReadByte / 255.0;
       blend[2] = ReadByte / 255.0;
       blend[3] = ReadByte / 255.0;
     }
     if (mask & 0x0800) fov = ReadByte;
     if (mask & 0x4000) rdflags = ReadByte;
     mask2 = ReadLong;
     for (i=0;i<32;i++) if (mask2 & (0x00000001 << i)) stats[i] = ReadShort;





  33..1199..  ppaacckkeetteennttiittiieess


     ID 0x12


     ppuurrppoossee
        Entity updates. _H_a_v_e _t_o come in a client side recording directly
        after a ppllaayyeerriinnffoo message and in a server side recording
        directly after a ffrraammee message.  This message is in fact a list
        of ssppaawwnnbbaasseelliinnee messages. Look there for a longer variable
        description.  The list ends with entity==0.
     vvaarriiaabblleess

        long mask;
           is used to reduce the network traffic.

        long entity;
           is the number of the entity.

        long remove;
           indicates a disappearing entity.

        vec3_t origin;
           is the origin.

        vec3_t angles;
           is the orientation.

        vec3_t old_origin;
           old origin (for client side prediction).

        long modelindex;
           is the model index.

        long modelindex2;
           is _w_e_a_p_o_n_s_, _C_T_F_, _f_l_a_g_s_, _e_t_c.

        long modelindex3;
           is _w_e_a_p_o_n_s_, _C_T_F_, _f_l_a_g_s_, _e_t_c.

        long modelindex4;
           is _w_e_a_p_o_n_s_, _C_T_F_, _f_l_a_g_s_, _e_t_c.

        long frame;
           is the frame of the model.

        long skin;
           is the number of the skin for the model.

        long effects;
           is the entity effect.

        long renderfx;
           are some special render flags.

        long solid;
           _f_o_r _c_l_i_e_n_t _s_i_d_e _p_r_e_d_i_c_t_i_o_n_, _8_*_(_b_i_t_s _0_-_4_) _i_s _x_/_y _r_a_d_i_u_s
           _8_*_(_b_i_t_s _5_-_9_) _i_s _z _d_o_w_n _d_i_s_t_a_n_c_e_, _8_(_b_i_t_s_1_0_-_1_5_) _i_s _z _u_p

        long sound;
           _f_o_r _l_o_o_p_i_n_g _s_o_u_n_d_s_, _t_o _g_u_a_r_a_n_t_e_e _s_h_u_t_o_f_f

        long event;
           _i_m_p_u_l_s_e _e_v_e_n_t_s _-_- _m_u_z_z_l_e _f_l_a_s_h_e_s_, _f_o_o_t_s_t_e_p_s_, _e_t_c _e_v_e_n_t_s _o_n_l_y
           _g_o _o_u_t _f_o_r _a _s_i_n_g_l_e _f_r_a_m_e_, _t_h_e_y _a_r_e _a_u_t_o_m_a_t_i_c_a_l_l_y _c_l_e_a_r_e_d
           _e_a_c_h _f_r_a_m_e


     ppaarrssee rroouuttiinnee








     for (;;) {
       mask = ReadByte;
       if (mask & 0x00000080) mask |= (ReadByte <<  8);
       if (mask & 0x00008000) mask |= (ReadByte << 16);
       if (mask & 0x00800000) mask |= (ReadByte << 24);
       entity = (mask & 0x00000100) ? ReadShort : ReadByte;
       if (entity >= MAX_EDICTS) error("CL_ParsePacketEntities: bad number:%i",entity);
       if (entity == 0) break;
       remove = (mask & 0x00000040) ? 1 : 0;
       if (mask & 0x00000800) modelindex = ReadByte;
       if (mask & 0x00100000) modelindex2 = ReadByte;
       if (mask & 0x00200000) modelindex3 = ReadByte;
       if (mask & 0x00400000) modelindex4 = ReadByte;
       if (mask & 0x00000010) frame = ReadByte;
       if (mask & 0x00020000) frame = ReadShort;
       if (mask & 0x00010000) {
         if (mask & 0x02000000) skin = ReadLong;
         else skin = ReadByte;
       }
       else {
         if (mask & 0x02000000) skin = ReadShort;
       }
       if (mask & 0x00004000) {
         if (mask & 0x00080000) effects = ReadLong;
         else effects = ReadByte;
       }
       else {
         if (mask & 0x00080000) effects = ReadShort;
       }
       if (mask & 0x00001000) {
         if (mask & 0x00040000) renderfx = ReadLong;
         else renderfx = ReadByte;
       }
       else {
         if (mask & 0x00040000) renderfx = ReadShort;
       }
       if (mask & 0x00000001) origin[0] = ReadCoord;
       if (mask & 0x00000002) origin[1] = ReadCoord;
       if (mask & 0x00000200) origin[2] = ReadCoord;
       if (mask & 0x00000400) angles[0] = ReadAngle;
       if (mask & 0x00000004) angles[1] = ReadAngle;
       if (mask & 0x00000008) angles[2] = ReadAngle;
       if (mask & 0x01000000) ReadPosition(old_origin);
       if (mask & 0x04000000) sound = ReadByte;
       event = (mask & 0x00000020) ? ReadByte : 0;
       if (mask & 0x08000000) solid = ReadShort;
     }






  33..2200..  ddeellttaappaacckkeetteennttiittiieess


     ID 0x13


     ppuurrppoossee
        Entity updates. May come after a ppaacckkeetteennttiittiieess block.


     ppaarrssee rroouuttiinnee


     unknown ??FIXME??





  33..2211..  ffrraammee


     ID 0x14


     ppuurrppoossee
        Sequence numbers to cope with UDP packet loss, delta encoding
        and portal border crossings. Start of the ppllaayyeerriinnffoo and
        ppaacckkeetteennttiittiieess messages.

        In server side recordings this message contains only the current
        frame number.


     vvaarriiaabblleess

        long seq1;
           is the sequence number of the current packet or frame. Since
           the Quake II server uses a fixed time gap of 100ms (10Hz)
           between game state changes seq1 / 10 is the time in seconds
           since the server started.

        long seq2;
           is the sequence number of the delta reference frame. The
           reference holds for both following ppllaayyeerriinnffoo and
           ppaacckkeetteennttiittiieess messages. The Quake II server has a table with
           some old entity states and get from each client the sequence
           number of frames, which arrived correctly at the client side.
           So the server can decide which most currently sended old
           frame should be used now as the delta encoding reference
           frame.  seq2 is -1 to reference to the ssppaawwnnbbaasseelliinnee values.

        long count;
           is the number of bytes in the areas array.

        #define MAX_MAP_AREAS 256
           is the maximum number of areas in a map.

        unsigned char areas[MAX_MAP_AREAS / 8];
           is the array which defines the areas to be rendered.  Each
           bit in the areas array stays for one area in the map.

        long frame;
           is the frame number in server side recordings and similar to
           seq1. I may rename it even to seq1 in a future revision.



     ppaarrssee rroouuttiinnee










     long uk_b1;

     if (serverdata.isdemo == RECORD_CLIENT || serverdata.isdemo == RECORD_NETWORK) {
       seq1 = ReadLong;
       seq2 = ReadLong;
       if (serverdata.serverversion != 26) uk_b1 = ReadByte;
       count = ReadByte;
       for (i=0;i<count;i++) areas[i] = ReadByte;
     }
     if (serverdata.isdemo == RECORD_SERVER) {
       frame = ReadLong;
     }





  44..  VVeerrssiioonn HHiissttoorryy aanndd AAcckknnoowwlleeddggeemmeennttss



     00..00..11,, 1133 DDeecceemmbbeerr,, 11999977

     +o  First version (working paper) completed.

     +o  Only based on the published game source.

     +o  Never ever published.


     00..00..22,, 2233 DDeecceemmbbeerr,, 11999977

     +o  Old 3.00 ID codes included.

     +o  Version info included.

     +o  All simple ID codes ok.

     +o  packetentities, deltapacketentities, playerinfo missing.

     +o  spawnbaseline is very difficult.

     +o  Never published.


     00..00..33,, 2277 DDeecceemmbbeerr,, 11999977

     +o  Old 3.00 ID codes removed. Nobody wants to know them.

     +o  spawnbaseline is ok now.

     +o  playerinfo ok.

     +o  packetentities should be ok.

     +o  ReadDir for temp_entity ok.

     +o  deltapacketentities missing.

     +o  Never published.


     00..00..44,, 2288 DDeecceemmbbeerr,, 11999977

     +o  SGML-Tools 1.0.2 used for formatting.

     +o  Some minor tweaks.


     00..00..55,, 11 JJaannuuaarryy,, 11999988

     +o  SGML-Tools 1.0.2 formatting problems solved.

     +o  Long #define tables removed.

     +o  More references to the source.


     00..00..66,, 1122 MMaarrcchh,, 11999988

     +o  Some details better. Many thanks to Kekoa Proundfoot
        (kekoa@graphics.stanford.edu).

     +o  PlanetQuake is the new home.

     +o  Compatible with Quake II up to version 3.14.

     +o  SGML-Tools 1.0.5 used.


     11..00..00,, 1177 JJuunnee,, 11999988

     +o  Thanks to Ben Swartzlander (swartz@rice.edu) for the config
        string index 30.

     +o  Changed some command names (sound volume, server protocol
        version, config string, print text).

     +o  Changed the coordinates in playerinfo to standard coordinates.

     +o  Most changes in variable types and names were necessary to
        reduce the total number of tokens in the Quake and Quake II text
        parser of LMPC.

     +o  Compatible with Quake II up to 3.15a.


     11..00..11,, 1155 JJuullyy,, 11999988

     +o  server side recording information included.

     +o  Compatible with Quake II up to 3.17.

     +o  Some hints on old_origin updates and sequence numbering.

     +o  SGML-Tools 1.0.7 used.